package com.yupi.yupicturebackend.aop;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.yupi.yupicturebackend.annotation.PerformanceMonitor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 性能监控切面
 * 用于监控方法执行时间和性能指标
 * 
 * @author yupi
 */
@Aspect
@Component
@Slf4j
public class PerformanceMonitorAspect {

    private final MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();

    /**
     * 性能监控切面
     *
     * @param joinPoint 切入点
     * @param performanceMonitor 性能监控注解
     * @return 方法执行结果
     * @throws Throwable 异常
     */
    @Around("@annotation(performanceMonitor)")
    public Object doMonitor(ProceedingJoinPoint joinPoint, PerformanceMonitor performanceMonitor) throws Throwable {
        // 获取方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = method.getName();
        
        // 构建监控上下文
        Map<String, Object> monitorContext = new HashMap<>();
        monitorContext.put("className", className);
        monitorContext.put("methodName", methodName);
        monitorContext.put("module", StrUtil.isNotBlank(performanceMonitor.module()) ? 
                performanceMonitor.module() : className);
        monitorContext.put("description", StrUtil.isNotBlank(performanceMonitor.value()) ? 
                performanceMonitor.value() : methodName);

        // 记录方法参数
        if (performanceMonitor.recordArgs()) {
            Object[] args = joinPoint.getArgs();
            monitorContext.put("args", args);
        }

        // 记录开始时间和内存使用情况
        long startTime = System.currentTimeMillis();
        MemoryUsage beforeMemory = null;
        if (performanceMonitor.memoryMonitor()) {
            beforeMemory = memoryMXBean.getHeapMemoryUsage();
            monitorContext.put("beforeMemoryUsed", beforeMemory.getUsed());
        }

        Object result = null;
        Throwable exception = null;
        
        try {
            // 执行目标方法
            result = joinPoint.proceed();
            
            // 记录返回结果
            if (performanceMonitor.recordResult() && result != null) {
                monitorContext.put("result", result);
            }
            
            return result;
        } catch (Throwable e) {
            exception = e;
            throw e;
        } finally {
            // 计算执行时间
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            monitorContext.put("executionTime", executionTime);

            // 记录内存使用情况
            if (performanceMonitor.memoryMonitor() && beforeMemory != null) {
                MemoryUsage afterMemory = memoryMXBean.getHeapMemoryUsage();
                long memoryUsed = afterMemory.getUsed() - beforeMemory.getUsed();
                monitorContext.put("afterMemoryUsed", afterMemory.getUsed());
                monitorContext.put("memoryDiff", memoryUsed);
            }

            // 记录异常信息
            if (exception != null) {
                monitorContext.put("exception", exception.getClass().getSimpleName());
                monitorContext.put("exceptionMessage", exception.getMessage());
            }

            // 根据监控级别和执行时间记录日志
            logPerformanceInfo(performanceMonitor, monitorContext, executionTime, exception);
        }
    }

    /**
     * 记录性能信息
     *
     * @param performanceMonitor 性能监控注解
     * @param monitorContext 监控上下文
     * @param executionTime 执行时间
     * @param exception 异常信息
     */
    private void logPerformanceInfo(PerformanceMonitor performanceMonitor, 
                                   Map<String, Object> monitorContext, 
                                   long executionTime, 
                                   Throwable exception) {
        
        String logMessage = buildLogMessage(monitorContext);
        
        // 根据监控级别决定日志记录方式
        switch (performanceMonitor.level()) {
            case DEBUG:
                log.debug("性能监控 - {}", logMessage);
                break;
            case INFO:
                if (exception != null) {
                    log.error("性能监控 - 方法执行异常 - {}", logMessage);
                } else {
                    log.info("性能监控 - {}", logMessage);
                }
                break;
            case WARN:
                if (executionTime > performanceMonitor.slowThreshold()) {
                    log.warn("性能监控 - 慢查询检测 - {}", logMessage);
                } else if (exception != null) {
                    log.error("性能监控 - 方法执行异常 - {}", logMessage);
                }
                break;
            case ERROR:
                if (exception != null) {
                    log.error("性能监控 - 方法执行异常 - {}", logMessage);
                }
                break;
        }

        // 如果是慢查询，额外记录警告日志
        if (executionTime > performanceMonitor.slowThreshold() && 
            performanceMonitor.level() != PerformanceMonitor.MonitorLevel.WARN) {
            log.warn("慢查询检测 - 方法 {}.{} 执行时间 {}ms 超过阈值 {}ms", 
                    monitorContext.get("className"), 
                    monitorContext.get("methodName"), 
                    executionTime, 
                    performanceMonitor.slowThreshold());
        }
    }

    /**
     * 构建日志消息
     *
     * @param monitorContext 监控上下文
     * @return 日志消息
     */
    private String buildLogMessage(Map<String, Object> monitorContext) {
        StringBuilder sb = new StringBuilder();
        sb.append("模块: ").append(monitorContext.get("module"));
        sb.append(", 方法: ").append(monitorContext.get("className"))
          .append(".").append(monitorContext.get("methodName"));
        sb.append(", 描述: ").append(monitorContext.get("description"));
        sb.append(", 执行时间: ").append(monitorContext.get("executionTime")).append("ms");
        
        if (monitorContext.containsKey("memoryDiff")) {
            sb.append(", 内存变化: ").append(monitorContext.get("memoryDiff")).append("字节");
        }
        
        if (monitorContext.containsKey("exception")) {
            sb.append(", 异常: ").append(monitorContext.get("exception"));
            sb.append(", 异常信息: ").append(monitorContext.get("exceptionMessage"));
        }
        
        return sb.toString();
    }
}
